package com.dongnao.dnhttp.ywynet;

import android.support.annotation.NonNull;
import android.util.Log;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Created by ywy on 2018-04-28.
 */
public class Dispatcher {

    //最多同时请求
    private int maxRequests;
    //同一个host同时最多请求
    private int maxRequestsPerHost;

    public Dispatcher() {
        this(64, 2);
    }

    public Dispatcher(int maxRequests, int maxRequestsPerHost) {
        this.maxRequests = maxRequests;
        this.maxRequestsPerHost = maxRequestsPerHost;
    }

    private ExecutorService executorService;


    /**
     * 等待执行队列
     */
    private final Deque<Call.AsyncCall> readyAsyncCalls = new ArrayDeque<>();

    /**
     * 正在执行队列
     */
    private final Deque<Call.AsyncCall> runningAsyncCalls = new ArrayDeque<>();


    public synchronized ExecutorService executorService(){
        if(executorService == null){
            ThreadFactory threadFactory = new ThreadFactory() {
                @Override
                public Thread newThread(@NonNull Runnable r) {
                    Thread result = new Thread(r , "Http Client");
                    return result;
                }
            };

            executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
                    new SynchronousQueue<Runnable>(), threadFactory);

        }

        return executorService;
    }


    public void enqueue(Call.AsyncCall call) {
        Log.e("Dispatcher", "同时有:" + runningAsyncCalls.size());
        Log.e("Dispatcher", "host同时有:" + runningCallsForHost(call));

        if(runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost ){
            Log.e("Dispatcher", "提交执行");
            runningAsyncCalls.add(call);
            executorService().execute(call);
        }else{
            Log.e("Dispatcher", "等待执行");
            readyAsyncCalls.add(call);
        }
    }

    private int runningCallsForHost(Call.AsyncCall call) {
        int result = 0;
        for (Call.AsyncCall asyncCall:runningAsyncCalls) {
            if(asyncCall.host().equals(call.host())){
                result++;
            }
        }
        return result;
    }

    public void finished(Call.AsyncCall asyncCall) {
        synchronized (this) {
            runningAsyncCalls.remove(asyncCall);
            //判断是否执行等待队列中的请求
            promoteCalls();
        }
    }

    private void promoteCalls() {
        if(runningAsyncCalls.size() >= maxRequests){
            return;
        }
        if(readyAsyncCalls.isEmpty()){
            return;
        }

        for (Iterator<Call.AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext() ;) {
            Call.AsyncCall call = i.next();
            if(runningCallsForHost(call) < maxRequestsPerHost){
                i.remove();
                runningAsyncCalls.add(call);
                executorService().execute(call);
            }
            if(runningAsyncCalls.size() >= maxRequests){
                return;
            }

        }

    }

}
